package baseFx.database.execute;

import baseFx.common.Action1T;
import baseFx.common.Action2T;
import baseFx.common.Assert;
import baseFx.common.EventDispatcher;
import baseFx.common.utils.ClassUtils;
import baseFx.database.DbEntity;
import baseFx.database.DbEntityCore;
import baseFx.database.SqlCore;
import baseFx.database.query.DbEntityQuery;
import baseFx.database.where.ExecuteWhere;
import baseFx.database.where.SetWhere;

public interface DbExecute extends SqlCore, DbEntityCore {
    EventDispatcher<DbExecuteBeforeArgs> eventBefore();

    EventDispatcher<DbExecuteAfterArgs> eventAfter();

    EventDispatcher<DbExecuteErrorArgs> eventError();

    DbEntityQuery query();

    <T> int insert(T model, Integer timeout);

    <T> int update(T set, ExecuteWhere<T> where, Integer timeout);

    <T> int setNull(T set, ExecuteWhere<T> where, Integer timeout);

    <T> int delete(ExecuteWhere<T> where, boolean force, Integer timeout);

    int proc(Object model, Integer timeout);

    default <T> int insert(T model) {
        return insert(model, null);
    }

    default <T> T insertby(Class<T> clazz, Action1T<T> action) {
        T model = ClassUtils.newInstance(clazz);
        action.execute(model);
        insert(model);
        return model;
    }

    default <T> int update(Class<T> table, T set, T where) {
        return update(set, new ExecuteWhere<T>(table) {
            @Override
            public T eq() {
                return where;
            }
        }, null);
    }

    default <T> int update(T set, T where) {
        return update((Class<? super T>) set.getClass(), set, where);
    }

    default <T> int update(Class<T> table, T model) {
        DbEntity entity = DbEntity.get(table);
        DbEntity.DbField id = entity.getFieldByColumnName("id");
        Assert.isNotNull(id, "实体中没有id字段");
        Object value = id.get(model);
        Assert.isNotNull(value, "id字段的值不能是空");
        T where = ClassUtils.newInstance(table);
        id.set(where, value);
        id.set(model, null);
        try {
            return update(table, model, where);
        } finally {
            id.set(model, value);
        }
    }

    default <T> int update(T model) {
        return update((Class<? super T>) model.getClass(), model);
    }

    default <T> int updateby(Class<T> table, Action1T<T> action) {
        T model = ClassUtils.newInstance(table);
        action.execute(model);
        return update(model);
    }

    default <T> int updateby(Class<T> table, Action2T<T, T> action) {
        T set = ClassUtils.newInstance(table);
        T where = ClassUtils.newInstance(table);
        action.execute(set, where);
        return update(set, new ExecuteWhere<T>(table) {
            @Override
            public T eq() {
                return where;
            }

            @Override
            public boolean allowEmptyCondition() {
                return false;
            }
        }, null);
    }

    default <T> int updateBy(Class<T> table, Action1T<T> set, Action1T<SetWhere<T>> where) {
        SetWhere<T> setWhere = new SetWhere<>(table);
        where.execute(setWhere);
        T setModel = ClassUtils.newInstance(table);
        set.execute(setModel);
        return update(setModel, setWhere.executeWhere(), null);
    }

    default <T> int setNull(Class<T> table, T set, T where) {
        return setNull(set, new ExecuteWhere<T>(table) {
            @Override
            public T eq() {
                return where;
            }
        }, null);
    }

    default <T> int setNull(T set, T where) {
        return setNull((Class<? super T>) set.getClass(), set, where);
    }

    default <T> int setNull(Class<T> table, T model) {
        DbEntity entity = DbEntity.get(table);
        DbEntity.DbField id = entity.getFieldByColumnName("id");
        Assert.isNotNull(id, "实体中没有id字段");
        Object value = id.get(model);
        Assert.isNotNull(value, "id字段的值不能是空");
        T where = ClassUtils.newInstance(table);
        id.set(where, value);
        id.set(model, null);
        try {
            return setNull(table, model, where);
        } finally {
            id.set(model, value);
        }
    }

    default <T> int setNull(T model) {
        return setNull((Class<? super T>) model.getClass(), model);
    }

    default <T> int setNullby(Class<T> table, Action1T<T> action) {
        T model = ClassUtils.newInstance(table);
        action.execute(model);
        return setNull(table, model);
    }

    default <T> int setNullby(Class<T> table, Action2T<T, T> action) {
        T set = ClassUtils.newInstance(table);
        T where = ClassUtils.newInstance(table);
        action.execute(set, where);
        return setNull(set, new ExecuteWhere<T>(table) {
            @Override
            public T eq() {
                return where;
            }

            @Override
            public boolean allowEmptyCondition() {
                return false;
            }
        }, null);
    }

    default <T> int setNullBy(Class<T> table, Action1T<T> set, Action1T<SetWhere<T>> where) {
        SetWhere<T> setWhere = new SetWhere<>(table);
        where.execute(setWhere);
        T setModel = ClassUtils.newInstance(table);
        set.execute(setModel);
        return setNull(setModel, setWhere.executeWhere(), null);
    }

    default <T> int delete(ExecuteWhere<T> where, Integer timeout) {
        return delete(where, false, timeout);
    }

    default <T> int forceDelete(ExecuteWhere<T> where) {
        return delete(where, true, null);
    }

    default <T> int delete(Class<T> table, T where) {
        return delete(new ExecuteWhere<T>(table) {
            @Override
            public T eq() {
                return where;
            }
        }, null);
    }

    default <T> int delete(T where) {
        return delete((Class<? super T>) where.getClass(), where);
    }

    default <T> int deleteby(Class<T> table, Action1T<T> action) {
        T where = ClassUtils.newInstance(table);
        action.execute(where);
        return delete(new ExecuteWhere<T>(table) {
            @Override
            public T eq() {
                return where;
            }

            @Override
            public boolean allowEmptyCondition() {
                return false;
            }
        }, null);
    }

    default <T> int deleteBy(Class<T> table, Action1T<SetWhere<T>> where) {
        SetWhere<T> setWhere = new SetWhere<>(table);
        where.execute(setWhere);
        return delete(setWhere.executeWhere(), null);
    }

    default int proc(Object model) {
        return proc(model, null);
    }

    default <T> int procby(Class<T> clazz, Action1T<T> action) {
        T model = ClassUtils.newInstance(clazz);
        action.execute(model);
        return proc(model);
    }
}
